﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace DeviceManager
{
    public class AutoReconnectTCPClient
    {
        public string m_Ip;
        protected int m_Port;
        protected IPEndPoint m_RemoteEP;

        protected Socket m_Client;
        bool m_AutoReconnect;
        int m_Timeout;

        byte[] m_ReadBuffer = new byte[1024*32];
        ManualResetEvent m_eventRecieve = new ManualResetEvent(false);

        bool m_NewDataRecieved = false;
        string m_LastResponse = "";

        byte[] m_RecvBuffer;

        public bool ConnectStatus = false;
        public string ClientType = "";
        System.Timers.Timer m_TimerHeartbeat;

        byte[] m_StartCommand;
        public byte[] StartCommand
        {
            get
            {
                return m_StartCommand;
            }
            set
            {
                m_StartCommand = value;
            }
        }

        public AutoReconnectTCPClient(string ip, int port)
        {
            m_Ip = ip;
            m_Port = port;
            m_Client = null;
            m_AutoReconnect = true;
            m_Timeout = 500;
        }



        public bool Connect()
        {
            if (m_Client != null) return true;

            if (m_RemoteEP == null)
            {
                try
                {
                    m_RemoteEP = new IPEndPoint(IPAddress.Parse(m_Ip), m_Port);
                }
                catch (Exception ex)
                {
                    m_RemoteEP = null;
                    m_Client = null;
                    return false;
                }
            }

            try
            {
                m_Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                m_Client.SendTimeout = m_Timeout;
                m_Client.ReceiveTimeout = m_Timeout;
                m_Client.Connect(m_RemoteEP);
                ConnectStatus = true;
                m_Client.BeginReceive(m_ReadBuffer, 0, m_ReadBuffer.Length, SocketFlags.None, new AsyncCallback(ReadCallBack), m_Client);
            }
            catch (Exception ex)
            {
                m_Client = null;
                ConnectStatus = false;
                return false;
            }
            return true;
        }

        void m_TimerHeartbeat_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (m_HeatbeatData != null)
                SendData(m_HeatbeatData);
        }


        private void ReadCallBack(IAsyncResult ar)
        {
            if (!ConnectStatus) return;
            try
            {
                int bytesRecieved = m_Client.EndReceive(ar);
                if (bytesRecieved == 0)
                {
                    Disconnect();
                    return;
                }
                m_NewDataRecieved = true;
                m_RecvBuffer = new byte[bytesRecieved];
                Buffer.BlockCopy(m_ReadBuffer, 0, m_RecvBuffer, 0, bytesRecieved);
                ProcessDataRecv(m_RecvBuffer);
                m_eventRecieve.Set();
                if (DataRecv != null)
                {
                    DataRecv(m_RecvBuffer);
                }
                m_Client.BeginReceive(m_ReadBuffer, 0, m_ReadBuffer.Length, SocketFlags.None, new AsyncCallback(ReadCallBack), m_Client);
            }
            catch (Exception ex2)
            {
                if (ServerDisconnected != null)
                    ServerDisconnected();
                Disconnect();
            }
        }

        public virtual void ProcessDataRecv(byte[] data)
        {
            m_LastResponse = System.Text.Encoding.Default.GetString(data);
        }

        public bool SendMsg(string msg)
        {
            return SendData(System.Text.Encoding.Default.GetBytes(msg));
        }

        public bool SendData(byte[] data)
        {
            lock (this)
            {
                if (m_AutoReconnect && m_Client == null)
                {
                    if (!Connect()) return false;
                }

                try
                {
                    m_Client.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(WriteCallBack), m_Client);
                }
                catch (Exception ex)
                {
                    if (ServerDisconnected != null)
                        ServerDisconnected();
                    Disconnect();
                }
            }
            return true;
        }

        public void WriteCallBack(IAsyncResult ar)
        {
            try
            {
                int i = m_Client.EndSend(ar);
                System.Diagnostics.Debug.WriteLine("i = " + i);
            }
            catch (Exception ex)
            {
                if (ServerDisconnected != null)
                    ServerDisconnected();
                Disconnect();
            }
        }


        /// <summary>
        /// 发送单个请求字符串并接收回复数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public string Request(string data)
        {
            try
            {
                m_eventRecieve.Reset();
                m_NewDataRecieved = false;
                SendMsg(data);
                m_eventRecieve.WaitOne(m_Timeout, false);
                if (!m_NewDataRecieved) return "";
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            return m_LastResponse;
        }

        public byte[] Request(byte[] data)
        {
            try
            {
                m_eventRecieve.Reset();
                m_NewDataRecieved = false;
                SendData(data);
                m_eventRecieve.WaitOne(m_Timeout, false);
                if (!m_NewDataRecieved) return new byte[] { };
            }
            catch (Exception ex)
            {
                ;
            }
            return m_RecvBuffer;
        }

        byte[] m_HeatbeatData;
        public byte[] HeatbeatData
        {
            get
            {
                return m_HeatbeatData;
            }
            set
            {
                m_HeatbeatData = value;
            }
        }

        int m_HeatbeatInterval = 30000;
        public int HeatbeatInterval
        {
            get
            {
                return m_HeatbeatInterval;
            }
            set
            {
                m_HeatbeatInterval = value;
            }
        }

        public bool Disconnect()
        {
            if (m_TimerHeartbeat != null)
            {
                m_TimerHeartbeat.Enabled = false;
                m_TimerHeartbeat.Dispose();
                m_TimerHeartbeat = null;
            }

            ConnectStatus = false;
            if (m_Client == null) return true;

            try
            {
                m_Client.Close();

            }
            catch (Exception ex)
            {
                ;
            }

            m_Client = null;

            return true;
        }


        public event DataRecvDelegate DataRecv;

        public delegate void DelegateServerDisconnected();
        public event DelegateServerDisconnected ServerDisconnected;
    }
    public delegate void DataRecvDelegate(byte[] data);
}
